/**
 * @file 
 * Tests for  expansion.  
 * Note  that tests  have  been written  for  int  type  only, but  the
 * understanding is  that if  the expansion functor works  for a  given data
 * type, the partition will work.
 */

#include <list>
#include <set>

#include <gtest/gtest.h>

#include "list_ops.h"

class int_expansion
{
 public:
  void operator() (int *i1, std::list<int*> *result) 
  {
    result->push_back(i1);
    result->push_back(i1);
  }
};

class int_equivalence
{
 public:
  bool operator() (int &i1, int &i2) {return i1 == i2;};
};


/**
 *  Tests for expansion.
 */
TEST(ExpansionTest, ResultTest )
{
  int data[] = {1,2,3,4,5};
  std::list<int*> list_of_data_pointers;
  list_of_data_pointers.push_back(&data[0]);
  list_of_data_pointers.push_back(&data[1]);
  list_of_data_pointers.push_back(&data[2]);
  list_of_data_pointers.push_back(&data[3]);
  list_of_data_pointers.push_back(&data[4]);

  std::list<int*> expected;
  expected.push_back(&data[0]);
  expected.push_back(&data[0]);
  expected.push_back(&data[1]);
  expected.push_back(&data[1]);
  expected.push_back(&data[2]);
  expected.push_back(&data[2]);
  expected.push_back(&data[3]);
  expected.push_back(&data[3]);
  expected.push_back(&data[4]);
  expected.push_back(&data[4]);

  std::list<int*> actual;

  int_expansion my;

  expand(&list_of_data_pointers, &actual, my);
  EXPECT_TRUE(actual == expected);
}

/**
 *  Tests for comparison of multimaps.
 */
TEST(PartitionTest, ResultTest)
{
  int data[] = {1,2,3,4,5,1,2,3,4,1,2,3,1,2,1};
   std::list<int*> list_of_data_pointers;
  list_of_data_pointers.push_back(&data[0]);
  list_of_data_pointers.push_back(&data[1]);
  list_of_data_pointers.push_back(&data[2]);
  list_of_data_pointers.push_back(&data[3]);
  list_of_data_pointers.push_back(&data[4]);
  list_of_data_pointers.push_back(&data[5]);
  list_of_data_pointers.push_back(&data[6]);
  list_of_data_pointers.push_back(&data[7]);
  list_of_data_pointers.push_back(&data[8]);
  list_of_data_pointers.push_back(&data[9]);
  list_of_data_pointers.push_back(&data[10]);
  list_of_data_pointers.push_back(&data[11]);
  list_of_data_pointers.push_back(&data[12]);
  list_of_data_pointers.push_back(&data[13]);
  list_of_data_pointers.push_back(&data[14]);

  std::set<std::set<int*> > expected;
  std::set<int*> temp;
  temp.insert(&data[0]);
  temp.insert(&data[5]);
  temp.insert(&data[9]);
  temp.insert(&data[12]);
  temp.insert(&data[14]);
  expected.insert(temp);
  temp.erase(temp.begin(), temp.end());
  temp.insert(&data[1]);
  temp.insert(&data[6]);
  temp.insert(&data[10]);
  temp.insert(&data[13]);
  expected.insert(temp);
  temp.erase(temp.begin(), temp.end());
  temp.insert(&data[2]);
  temp.insert(&data[7]);
  temp.insert(&data[11]);
  expected.insert(temp);
  temp.erase(temp.begin(), temp.end());
  temp.insert(&data[3]);
  temp.insert(&data[8]);
  expected.insert(temp);
  temp.erase(temp.begin(), temp.end());
  temp.insert(&data[4]);
  expected.insert(temp);
  temp.erase(temp.begin(), temp.end());

  std::set<std::set<int*> > actual;

  int_equivalence my;

  partition(&list_of_data_pointers, &actual, my);
  EXPECT_TRUE(actual == expected);
}

/**
 *  Test for delete identical.
 */
TEST(DeleteIdenticalTest, ResultTest )
{
  int data[] = {1,2,3,4,5,1,2,3,4,1,2,3,1,2,1};
  std::list<int*> list_of_data_pointers;
  list_of_data_pointers.push_back(&data[0]);
  list_of_data_pointers.push_back(&data[1]);
  list_of_data_pointers.push_back(&data[2]);
  list_of_data_pointers.push_back(&data[3]);
  list_of_data_pointers.push_back(&data[4]);
  list_of_data_pointers.push_back(&data[5]);
  list_of_data_pointers.push_back(&data[6]);
  list_of_data_pointers.push_back(&data[7]);
  list_of_data_pointers.push_back(&data[8]);
  list_of_data_pointers.push_back(&data[9]);
  list_of_data_pointers.push_back(&data[10]);
  list_of_data_pointers.push_back(&data[11]);
  list_of_data_pointers.push_back(&data[12]);
  list_of_data_pointers.push_back(&data[13]);
  list_of_data_pointers.push_back(&data[14]);

  std::list<int*> expected;
  expected.push_back(&data[0]);
  expected.push_back(&data[1]);
  expected.push_back(&data[2]);
  expected.push_back(&data[3]);
  expected.push_back(&data[4]);

  std::list<int*> actual;

  int_equivalence my;

  delete_identical(&list_of_data_pointers, &actual, my);
  EXPECT_TRUE(actual == expected);
}
